跳到主要内容

面板 Panel

Panel 是 HiEasyX 里最自由的容器之一。它就是一个矩形的子区域——可以带背景色、可以带边框、可以裁剪内容,也可以完全透明无痕。你可以把它理解成 HTML 里的 <div>:本身没有视觉样式(除非你给),但提供了独立的布局上下文。

一句话理解

Panel = 一块空地 + 围墙(可选)。你在里面放什么、怎么放,完全自由。


函数原型

bool BeginPanel(const HXString &Id, PanelProfile &Profile);
void EndPanel(PanelProfile &Profile);

参数说明

参数类型说明
Idconst HXString &面板的唯一标识,用于状态持久化。使用 HXStr("id") 或 `L"id"。
ProfilePanelProfile &面板的配置结构体。必须是 static 或全局变量

返回值

类型说明
booltrue —— 面板可见且未折叠,你应该继续往里面放控件。
false —— 面板被折叠或不可见,跳过内部绘制。

PanelProfile 结构体

字段类型默认值说明
SizeHXPoint{-1, -1}面板尺寸。{-1, -1} 表示自动根据内容计算。
PaddingHXGInt5内边距:面板边界到内部控件的距离。
MarginHXGInt5外边距:面板与外部其他控件的距离。
DirectionHXLayoutDirectionVertical内部布局方向:Vertical(垂直)或 Horizontal(水平)。
ItemAlignHXLayoutAlignStretch子控件的对齐方式:StartCenterEndStretch
BackgroundColorHXColor{0,0,0,0}背景色。默认完全透明(ARGB 中 A=0)。
BorderColorHXColor{0,0,0,0}边框颜色。默认透明,即无边框。
BorderThicknessHXGInt1边框粗细(像素)。仅在 BorderColor 不透明时可见。
ClipContentboolfalse是否裁剪超出面板边界的内容。
关于 Size = -1

自动大小模式下,Panel 会根据内部控件的总尺寸 + Padding 来计算自己的宽高。这在内容动态变化时非常方便;但如果你在做固定布局(比如左侧边栏),建议手动指定 Size


无边框子区域

最基础的用法:一个透明的布局隔离区。

static HX::PanelProfile pp;
// 所有颜色保持默认透明,Direction 保持 Vertical
if (HX::BeginPanel(HXStr("content"), pp)) {
HX::Text(HXStr("这段内容在一个独立的 Panel 里"));
HX::Button(HXStr("按钮"), bp);
HX::EndPanel(pp);
}

虽然看起来和直接放在窗口里没区别,但 Panel 提供了独立的 PaddingDirection。比如你想让内部控件有额外的左边距,可以调 pp.Padding


背景色与边框

给 Panel 加点样式,让它成为视觉上的"卡片":

static HX::PanelProfile card;
card.Size = {300, 150};
card.Padding = 15;
card.BackgroundColor = HXColor{45, 45, 50, 255}; // 深灰背景
card.BorderColor = HXColor{80, 80, 90, 255}; // 浅灰边框
card.BorderThickness = 1;

if (HX::BeginPanel(HXStr("card1"), card)) {
HX::Text(HXStr("卡片标题"));
HX::Text(HXStr("卡片内容文字..."));
HX::EndPanel(card);
}

裁剪内容

当 Panel 内部内容超出其尺寸时,默认是会"溢出来"的。如果你希望超出部分被剪掉(比如一个固定大小的滚动区域),开启 ClipContent

static HX::PanelProfile clipPanel;
clipPanel.Size = {200, 100};
clipPanel.ClipContent = true;

if (HX::BeginPanel(HXStr("clip"), clipPanel)) {
// 如果这段文字或控件高度超过 100px,超出的部分会被裁剪掉
HX::Text(HXStr("这是一段很长的内容..."));
HX::EndPanel(clipPanel);
}
配合 Scroller 使用

ClipContent 通常和 Scroller 一起使用:Panel 负责定死可视区域的大小,Scroller 负责处理滚动偏移和滚动条。不过注意,BeginPanel 本身不会创建滚动条,它只是裁剪。


内部独立布局上下文

Panel 最重要的特性是:它 push 了一个全新的 HXLayoutContext

这意味着:

  • Panel 内部的 BaseLine 从 Panel 的 Padding 处开始计算
  • Panel 内部的 ControlGap 不影响外部
  • Panel 可以设置自己的 DirectionHorizontal,而外部仍然是 Vertical
HX::Window(HXStr("演示"), wp);

// 外部是默认垂直布局
HX::Text(HXStr("外部文本 1"));

static HX::PanelProfile inner;
inner.Size = {-1, 60};
inner.Direction = HX::HXLayoutDirection::Horizontal; // 内部改为水平!
inner.Padding = 8;

if (HX::BeginPanel(HXStr("toolbar"), inner)) {
HX::Button(HXStr("A"), bp); // 水平排列
HX::Button(HXStr("B"), bp);
HX::Button(HXStr("C"), bp);
HX::EndPanel(inner);
}

// 离开 Panel 后,恢复外部垂直布局
HX::Text(HXStr("外部文本 2"));

完整示例代码

#include <include/hex.h>
#include <include/impl/EasyX/hex_impl_easyx.h>

int main() {
initgraph(800, 600);
setbkcolor(WHITE);
cleardevice();

HX::HXInitForEasyX();
HX::SetBuffer(GetWorkingImage());

BeginBatchDraw();

static HX::WindowProfile wp;
wp.Size = {500, 450};

static HX::ButtonProfile bp;
static float val = 0.3f;
static HX::SliderProfile1f sp;

while (true) {
HX::HXBegin();

ExMessage msg;
while (peekmessage(&msg)) {
HX::PushMessage(HX::GetHXMessage(&msg));
}

HX::Window(HXStr("Panel 演示"), wp);

// ---------- 透明 Panel:只是隔离布局 ----------
static HX::PanelProfile transparent;
transparent.Padding = 20; // 内部有 20px 的内边距
if (HX::BeginPanel(HXStr("p1"), transparent)) {
HX::Text(HXStr("这个 Panel 完全透明"));
HX::Text(HXStr("但内部有 20px 的内边距"));
HX::EndPanel(transparent);
}

// ---------- 带背景色的卡片 ----------
static HX::PanelProfile card;
card.Size = {400, 120};
card.Padding = 12;
card.BackgroundColor = HXColor{50, 50, 58, 255};
card.BorderColor = HXColor{90, 90, 100, 255};
card.BorderThickness = 1;
if (HX::BeginPanel(HXStr("p2"), card)) {
HX::Text(HXStr("设置面板"));
HX::Slider1f(HXStr("音量"), val, sp);
HX::EndPanel(card);
}

// ---------- 内部水平布局的 Panel ----------
static HX::PanelProfile toolbar;
toolbar.Size = {-1, 50};
toolbar.Direction = HX::HXLayoutDirection::Horizontal;
toolbar.Padding = 8;
toolbar.BackgroundColor = HXColor{40, 40, 45, 255};
if (HX::BeginPanel(HXStr("p3"), toolbar)) {
HX::Button(HXStr("复制"), bp);
HX::Button(HXStr("粘贴"), bp);
HX::Button(HXStr("剪切"), bp);
HX::EndPanel(toolbar);
}

HX::End();
HX::Render();
FlushBatchDraw();
Sleep(16);
}

closegraph();
return 0;
}
Panel vs Group

Panel 没有标题栏,适合作为纯粹的布局容器或视觉卡片;Group 自带标题和边框,适合功能分组。详见 [分组 Group](./分组 Group)。